home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / PCGPEV10.ZIP / TUT7.TXT < prev    next >
Text File  |  1994-05-05  |  48KB  |  1,196 lines

  1.                    ╒═══════════════════════════════╕
  2.                    │         W E L C O M E         │
  3.                    │  To the VGA Trainer Program   │ │
  4.                    │              By               │ │
  5.                    │      DENTHOR of ASPHYXIA      │ │ │
  6.                    ╘═══════════════════════════════╛ │ │
  7.                      ────────────────────────────────┘ │
  8.                        ────────────────────────────────┘
  9.  
  10.                            --==[ PART 7 ]==--
  11.  
  12.  
  13.  
  14. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  15. ■ Introduction
  16.  
  17. Hello! By popular request, this part is all about animation. I will be
  18. going over three methods of doing animation on a PC, and will
  19. concerntrate specifically on one, which will be demonstrated in the
  20. attached sample code.
  21.  
  22. Although not often used in demo coding, animation is usually used in
  23. games coding, which can be almost as rewarding ;-)
  24.  
  25. In this part I will also be a lot less stingy with assembler code :)
  26. Included will be a fairly fast pure assembler putpixel, an asm screen
  27. flip command, an asm icon placer, an asm partial-flip and one or two
  28. others. I will be explaining how these work in detail, so this may also
  29. be used as a bit of an asm-trainer too.
  30.  
  31. By the way, I apologise for this part taking so long to be released, but
  32. I only finished my exams a few days ago, and they of course took
  33. preference ;-). I have also noticed that the MailBox BBS is no longer
  34. operational, so the trainer will be uploaded regularly to the BBS lists
  35. shown at the end of this tutorial.
  36.  
  37. If you would like to contact me, or the team, there are many ways you
  38. can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
  39.                   on the ASPHYXIA BBS.
  40.             2) Write a message in the Programming conference on the
  41.                   For Your Eyes Only BBS (of which I am the Moderator )
  42.                   This is preferred if you have a general programming query
  43.                   or problem others would benefit from.
  44.             4) Write to Denthor, Eze or Livewire on Connectix.
  45.             5) Write to :  Grant Smith
  46.                            P.O.Box 270 Kloof
  47.                            3640
  48.                            Natal
  49.             6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
  50.                   call during varsity)
  51.             7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and
  52.                   mention the word Denthor near the top of the letter.
  53.  
  54. NB : If you are a representative of a company or BBS, and want ASPHYXIA
  55.        to do you a demo, leave mail to me; we can discuss it.
  56. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
  57.         quite lonely and want to meet/help out/exchange code with other demo
  58.         groups. What do you have to lose? Leave a message here and we can work
  59.         out how to transfer it. We really want to hear from you!
  60.  
  61.  
  62.  
  63. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  64. ■  The Principals of Animation
  65.  
  66. I am sure all of you have seen a computer game with animation at one or
  67. other time. There are a few things that an animation sequence must do in
  68. order to give an impression of realism. Firstly, it must move,
  69. preferably using different frames to add to the realism (for example,
  70. with a man walking you should have different frames with the arms an
  71. legs in different positions). Secondly, it must not destroy the
  72. background, but restore it after it has passed over it.
  73.  
  74. This sounds obvious enough, but can be very difficult to code when you
  75. have no idea of how to go about achieving that.
  76.  
  77. In this trainer I will discuss various methods of meeting these two
  78. objectives.
  79.  
  80.  
  81.  
  82. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  83. ■  Frames and Object Control
  84.  
  85. It is quite obvious that for most animation to succeed, you must have
  86. numerous frames of the object in various poses (such as a man with
  87. several frames of him walking). When shown one after the other, these
  88. give the impression of natural movement.
  89.  
  90. So, how do we store these frames? I hear you cry. Well, the obvious
  91. method is to store them in arrays. After drawing a frame in Autodesk
  92. Animator and saving it as a .CEL, we usually use the following code to
  93. load it in :
  94.  
  95. TYPE icon = Array [1..50,1..50] of byte;
  96.  
  97. VAR tree : icon;
  98.  
  99. Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
  100. var
  101.   Fil : file;
  102.   Buf : array [1..1024] of byte;
  103.   BlocksRead, Count : word;
  104. begin
  105.   assign (Fil, FileName);
  106.   reset (Fil, 1);
  107.   BlockRead (Fil, Buf, 800);    { Read and ignore the 800 byte header }
  108.   Count := 0; BlocksRead := $FFFF;
  109.   while (not eof (Fil)) and (BlocksRead <> 0) do begin
  110.     BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);
  111.     Count := Count + 1024;
  112.   end;
  113.   close (Fil);
  114. end;
  115.  
  116. BEGIN
  117.   Loadcel ('Tree.CEL',addr (tree));
  118. END.
  119.  
  120. We now have the 50x50 picture of TREE.CEL in our array tree. We may access
  121. this array in the usual manner (eg. col:=tree [25,30]). If the frame is
  122. large, or if you have many frames, try using pointers (see previous
  123. parts)
  124.  
  125. Now that we have the picture, how do we control the object? What if we
  126. want multiple trees wandering around doing their own thing? The solution
  127. is to have a record of information for each tree. A typical data
  128. structure may look like the following :
  129.  
  130. TYPE Treeinfo = Record
  131.                   x,y:word;       { Where the tree is }
  132.                   speed:byte;     { How fast the tree is moving }
  133.                   Direction:byte; { Where the tree is facing }
  134.                   frame:byte      { Which animation frame the tree is
  135.                                     currently involved in }
  136.                   active:boolean; { Is the tree actually supposed to be
  137.                                     shown/used? }
  138.                 END;
  139.  
  140. VAR Forest : Array [1..20] of Treeinfo;
  141.  
  142. You now have 20 trees, each with their own information, location etc.
  143. These are accessed using the following means :
  144.                   Forest [15].x:=100;
  145. This would set the 15th tree's x coordinate to 100.
  146.  
  147.  
  148.  
  149. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  150. ■  Restoring the Overwritten Background
  151.  
  152. I will discuss three methods of doing this. These are NOT NECESSARILY
  153. THE ONLY OR BEST WAYS TO DO THIS! You must experiment and decide which
  154. is the best for your particular type of program.
  155.  
  156. METHOD 1 :
  157.  
  158. Step 1 : Create two virtual pages, Vaddr and Vaddr2.
  159. Step 2 : Draw the background to Vaddr2.
  160. Step 3 : Flip Vaddr2 to Vaddr.
  161. Step 4 : Draw all the foreground objects onto Vaddr.
  162. Step 5 : Flip Vaddr to VGA.
  163. Step 6 : Repeat from 3 continuously.
  164.  
  165. In ascii, it looks like follows ...
  166.  
  167.     +---------+           +---------+           +---------+
  168.     |         |           |         |           |         |
  169.     |  VGA    | <=======  |  VADDR  |  <======  |  VADDR2 |
  170.     |         |           | (bckgnd)|           | (bckgnd)|
  171.     |         |           |+(icons) |           |         |
  172.     +---------+           +---------+           +---------+
  173.  
  174. The advantages of this approach is that it is straightforward, continual
  175. reading of the background is not needed, there is no flicker and it is
  176. simple to implement.  The disadvantages are that two 64000 byte virtual
  177. screens are needed, and the procedure is not very fast because of the
  178. slow speed of flipping.
  179.  
  180.  
  181. METHOD 2 :
  182.  
  183. Step 1 : Draw background to VGA.
  184. Step 2 : Grab portion of background that icon will be placed on.
  185. Step 3 : Place icon.
  186. Step 4 : Replace portion of background from Step 2 over icon.
  187. Step 5 : Repeat from step 2 continuously.
  188.  
  189. In terms of ascii ...
  190.  
  191.       +---------+
  192.       |      +--|------- + Background restored (3)
  193.       |      * -|------> * Background saved to memory (1)
  194.       |      ^  |
  195.       |      +--|------- # Icon placed (2)
  196.       +---------+
  197.  
  198. The advantages of this method is that very little extra memory is
  199. needed. The disadvantages are that writing to VGA is slower then writing
  200. to memory, and there may be large amounts of flicker.
  201.  
  202.  
  203. METHOD 3 :
  204.  
  205. Step 1 : Set up one virtual screen, VADDR.
  206. Step 2 : Draw background to VADDR.
  207. Step 3 : Flip VADDR to VGA.
  208. Step 4 : Draw icon to VGA.
  209. Step 5 : Transfer background portion from VADDR to VGA.
  210. Step 6 : Repeat from step 4 continuously.
  211.  
  212. In ascii ...
  213.  
  214.      +---------+           +---------+
  215.      |         |           |         |
  216.      |   VGA   |           |  VADDR  |
  217.      |         |           | (bckgnd)|
  218.      | Icon>* <|-----------|--+      |
  219.      +---------+           +---------+
  220.  
  221. The advantages are that writing from the virtual screen is quicker then
  222. from VGA, and there is less flicker then in Method 2. Disadvantages are
  223. that you are using a 64000 byte virtual screen, and flickering occurs
  224. with large numbers of objects.
  225.  
  226. In the attached sample program, a mixture of Method 3 and Method 1 is
  227. used. It is faster then Method 1, and has no flicker, unlike Method 3.
  228. What I do is I use VADDR2 for background, but only restore the
  229. background that has been changed to VADDR, before flipping to VGA.
  230.  
  231. In the sample program, you will see that I restore the entire background
  232. of each of the icons, and then place all the icons. This is because if I
  233. replace the background then place the icon on each object individually,
  234. if two objects are overlapping, one is partially overwritten.
  235.  
  236. The following sections are explanations of how the various assembler
  237. routines work. This will probably be fairly boring for you if you
  238. already know assembler, but should help beginners and dabblers alike.
  239.  
  240.  
  241. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  242. ■  The ASM Putpixel
  243.  
  244. To begin with, I will explain a few of the ASM variables and functions :
  245.  
  246. <NOTE THAT THIS IS AN EXTREMELY SIMPLISTIC VIEW OF ASSEMBLY LANGUAGE!
  247. There are numerous books to advance your knowledge, and the Norton
  248. Guides assembler guide  may be invaluable for people beginning to code
  249. in assembler. I haven't given you the pretty pictures you are supposed
  250. to have to help you understand it easier, I have merely laid it out like
  251. a programming language with it's own special procedures. >
  252.  
  253. There are 4 register variables : AX,BX,CX,DX. These are words (double
  254. bytes) with a range from 0 to 65535. You may access the high and low
  255. bytes of these by replacing the X with a "H" for high or "L" for low.
  256. For example, AL has a range from 0-255.
  257.  
  258. You also have two pointers : ES:DI and DS:SI. The part on the left is
  259. the segment to which you are pointing (eg $a000), and the right hand
  260. part is the offset, which is how far into the segment you are pointing.
  261. Turbo Pascal places a variable over 16k into the base of a segment, ie.
  262. DI or SI will be zero at the start of the variable.
  263.  
  264. If you wish to be pointing to pixel number 3000 on the VGA screen (see
  265. previous parts for the layout of the VGA screen), ES would be equal to
  266. $a000 and DI would be equal to 3000.  You can quite as easily make ES or
  267. DS be equal to the offset of a virtual screen.
  268.  
  269. Here are a few functions that you will need to know :
  270.  
  271.       mov   destination,source       This moves the value in source to
  272.                                      destination. eg  mov ax,50
  273.       add   destination,source       This adds source to destination,
  274.                                      the result being stored in destination
  275.       mul   source                   This multiplies AX by source. If
  276.                                      source is a byte, the source is
  277.                                      multiplied by AL, the result being
  278.                                      stored in AX. If source is a word,
  279.                                      the source is multiplied by AX, the
  280.                                      result being stored in DX:AX
  281.       movsb                          This moves the byte that DS:SI is
  282.                                      pointing to into ES:DI, and
  283.                                      increments SI and DI.
  284.       movsw                          Same as movsb except it moves a
  285.                                      word instead of a byte.
  286.       stosw                          This moves AX into ES:DI. stosb
  287.                                      moves AL into ES:DI. DI is then
  288.                                      incremented.
  289.       push register                  This saves the value of register by
  290.                                      pushing it onto the stack. The
  291.                                      register may then be altered, but
  292.                                      will be restored to it's original
  293.                                      value when popped.
  294.       pop register                   This restores the value of a pushed
  295.                                      register. NOTE : Pushed values must
  296.                                      be popped in the SAME ORDER but
  297.                                      REVERSED.
  298.       rep  command                   This repeats Command by as many
  299.                                      times as the value in CX
  300.  
  301.  
  302. SHL Destination,count      ;
  303. and SHR Destination,count  ;
  304. need a bit more explaining. As you know, computers think in ones and
  305. zeroes. Each number may be represented in this base 2 operation. A byte
  306. consists of 8 ones and zeroes (bits), and have a range from 0 to 255. A 
  307. word consists of 16 ones and zeroes (bits), and has a range from 0 to 
  308. 65535. A double word consists of 32 bits.
  309.  
  310. The number 53 may be represented as follows :  00110101.  Ask someone who
  311. looks clever to explain to you how to convert from binary to decimal and
  312. vice-versa.
  313.  
  314. What happens if you shift everything to the left? Drop the leftmost
  315. number and add a zero to the right? This is what happens :
  316.  
  317.                 00110101     =  53
  318.                  <-----
  319.                 01101010     =  106
  320.  
  321. As you can see, the value has doubled! In the same way, by shifting one
  322. to the right, you halve the value! This is a VERY quick way of
  323. multiplying or dividing by 2. (note that for dividing by shifting, we
  324. get the trunc of the result ... ie.  15 shr 1 = 7)
  325.  
  326. In assembler the format is SHL destination,count    This shifts
  327. destination by as many bits in count (1=*2, 2=*4, 3=*8, 4=*16 etc)
  328. Note that a shift takes only 2 clock cycles, while a mul can take up to 133
  329. clock cycles. Quite a difference, no? Only 286es or above may have count
  330. being greater then one.
  331.  
  332. This is why to do the following to calculate the screen coordinates for
  333. a putpixel is very slow :
  334.  
  335.            mov    ax,[Y]
  336.            mov    bx,320
  337.            mul    bx
  338.            add    ax,[X]
  339.            mov    di,ax
  340.  
  341. But alas! I hear you cry. 320 is not a value you may shift by, as you
  342. may only shift by 2,4,8,16,32,64,128,256,512 etc.etc. The solution is
  343. very cunning. Watch.
  344.  
  345.     mov     bx,[X]
  346.     mov     dx,[Y]
  347.     push    bx
  348.     mov     bx, dx                  {; bx = dx = Y}
  349.     mov     dh, dl                  {; dh = dl = Y}
  350.     xor     dl, dl                  {; These 2 lines equal dx*256 }
  351.     shl     bx, 1
  352.     shl     bx, 1
  353.     shl     bx, 1
  354.     shl     bx, 1
  355.     shl     bx, 1
  356.     shl     bx, 1                   {; bx = bx * 64}
  357.     add     dx, bx                  {; dx = dx + bx (ie y*320)}
  358.     pop     bx                      {; get back our x}
  359.     add     bx, dx                  {; finalise location}
  360.     mov     di, bx
  361.  
  362. Let us have a look at this a bit closer shall we?
  363. bx=dx=y        dx=dx*256  ;   bx=bx*64     ( Note, 256+64 = 320 )
  364.  
  365. dx+bx=Correct y value, just add X!
  366.  
  367. As you can see, in assembler, the shortest code is often not the
  368. fastest.
  369.  
  370. The complete putpixel procedure is as follows :
  371.  
  372. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
  373.   { This puts a pixel on the screen by writing directly to memory. }
  374. BEGIN
  375.   Asm
  376.     push    ds                      {; Make sure these two go out the }
  377.     push    es                      {; same they went in }
  378.     mov     ax,[where]
  379.     mov     es,ax                   {; Point to segment of screen }
  380.     mov     bx,[X]
  381.     mov     dx,[Y]
  382.     push    bx                      {; and this again for later}
  383.     mov     bx, dx                  {; bx = dx}
  384.     mov     dh, dl                  {; dx = dx * 256}
  385.     xor     dl, dl
  386.     shl     bx, 1
  387.     shl     bx, 1
  388.     shl     bx, 1
  389.     shl     bx, 1
  390.     shl     bx, 1
  391.     shl     bx, 1                   {; bx = bx * 64}
  392.     add     dx, bx                  {; dx = dx + bx (ie y*320)}
  393.     pop     bx                      {; get back our x}
  394.     add     bx, dx                  {; finalise location}
  395.     mov     di, bx                  {; di = offset }
  396.     {; es:di = where to go}
  397.     xor     al,al
  398.     mov     ah, [Col]
  399.     mov     es:[di],ah              {; move the value in ah to screen
  400.                                        point es:[di] }
  401.     pop     es
  402.     pop     ds
  403.   End;
  404. END;
  405.  
  406. Note that with DI and SI, when you use them :
  407.       mov   di,50      Moves di to position 50
  408.       mov   [di],50    Moves 50 into the place di is pointing to
  409.  
  410.  
  411. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  412. ■  The Flip Procedure
  413.  
  414. This is fairly straightforward. We get ES:DI to point to the start of
  415. the destination screen, and DS:SI to point to the start of the source
  416. screen, then do 32000 movsw (64000 bytes).
  417.  
  418. procedure flip(source,dest:Word);
  419.   { This copies the entire screen at "source" to destination }
  420. begin
  421.   asm
  422.     push    ds
  423.     mov     ax, [Dest]
  424.     mov     es, ax                  { ES = Segment of source }
  425.     mov     ax, [Source]
  426.     mov     ds, ax                  { DS = Segment of source }
  427.     xor     si, si                  { SI = 0   Faster then mov si,0 }
  428.     xor     di, di                  { DI = 0 }
  429.     mov     cx, 32000
  430.     rep     movsw                   { Repeat movsw 32000 times }
  431.     pop     ds
  432.   end;
  433. end;
  434.  
  435. The cls procedure works in much the same way, only it moves the color
  436. into AX then uses a rep stosw (see program for details)
  437.  
  438. The PAL command is almost exactly the same as it's Pascal equivalent
  439. (see previous tutorials). Look in the sample code to see how it uses the
  440. out and in commands.
  441.  
  442.  
  443. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  444. ■  In Closing
  445.  
  446. The assembler procedures presented to you in here are not at their best.
  447. Most of these are procedures ASPHYXIA abandoned for better ones after
  448. months of use. But, as you will soon see, they are all MUCH faster then
  449. the original Pascal equivalents I originally gave you. In future, I
  450. hope to give you more and more assembler procedures for your ever
  451. growing collections. But, as you know, I am not always very prompt with
  452. this series (I don't know if even one has been released within one week
  453. of the previous one), so if you want to get any stuff done, try do it
  454. yourself. What do you have to lose, aside from your temper and a few
  455. rather inventive reboots ;-)
  456.  
  457. What should I do for the next trainer? A simple 3-d tutorial? You may
  458. not like it, because I would go into minute detail of how it works :)
  459. Leave me suggestions for future trainers by any of the means discussed
  460. at the top of this trainer.
  461.  
  462. After the customary quote, I will place a listing of the BBSes I
  463. currently know that regularly carry this Trainer Series. If your BBS
  464. receives it regularly, no matter where in the country you are, get a
  465. message to me and I'll add it to the list. Let's make it more convenient
  466. for locals to grab a copy without calling long distance ;-)
  467.  
  468.             [  There they sit, the preschooler class encircling their
  469.                   mentor, the substitute teacher.
  470.                "Now class, today we will talk about what you want to be
  471.                   when you grow up. Isn't that fun?" The teacher looks
  472.                   around and spots the child, silent, apart from the others
  473.                   and deep in thought. "Jonny, why don't you start?" she
  474.                   encourages him.
  475.                Jonny looks around, confused, his train of thought
  476.                   disrupted. He collects himself, and stares at the teacher
  477.                   with a steady eye. "I want to code demos," he says,
  478.                   his words becoming stronger and more confidant as he
  479.                   speaks. "I want to write something that will change
  480.                   peoples perception of reality. I want them to walk
  481.                   away from the computer dazed, unsure of their footing
  482.                   and eyesight. I want to write something that will
  483.                   reach out of the screen and grab them, making
  484.                   heartbeats and breathing slow to almost a halt. I want
  485.                   to write something that, when it is finished, they
  486.                   are reluctant to leave, knowing that nothing they
  487.                   experience that day will be quite as real, as
  488.                   insightful, as good. I want to write demos."
  489.                Silence. The class and the teacher stare at Jonny, stunned. It
  490.                   is the teachers turn to be confused. Jonny blushes,
  491.                   feeling that something more is required.  "Either that
  492.                   or I want to be a fireman."
  493.                                                                      ]
  494.                                                        - Grant Smith
  495.                                                             14:32
  496.                                                                21/11/93
  497.  
  498. See you next time,
  499.   - DENTHOR
  500.  
  501. These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)
  502.  
  503. ╔══════════════════════════╦════════════════╦═════╦═══╦════╦════╗
  504. ║BBS Name                  ║Telephone No.   ║Open ║Msg║File║Past║
  505. ╠══════════════════════════╬════════════════╬═════╬═══╬════╬════╣
  506. ║ASPHYXIA BBS #1           ║(031) 765-5312  ║ALL  ║ * ║ *  ║ *  ║
  507. ║ASPHYXIA BBS #2           ║(031) 765-6293  ║ALL  ║ * ║ *  ║ *  ║
  508. ║Connectix BBS             ║(031) 266-9992  ║ALL  ║ * ║ *  ║ *  ║
  509. ║For Your Eyes Only BBS    ║(031) 285-318   ║A/H  ║ * ║ *  ║ *  ║
  510. ╚══════════════════════════╩════════════════╩═════╩═══╩════╩════╝
  511.  
  512. Open = Open at all times or only A/H
  513. Msg  = Available in message base
  514. File = Available in file base
  515. Past = Previous Parts available
  516.  
  517.  
  518. ┌──────────────┬─────────────────────────────────────────────────────────────
  519. │ TUTPROG7.PAS │
  520. └──────────────┘
  521.  
  522. {$X+}
  523. USES crt;
  524.  
  525. CONST VGA = $a000;
  526.  
  527. Type Toastinfo = Record                 { This is format of of each of our }
  528.                  x,y:integer;              { records for the flying toasters }
  529.                  speed,frame:integer;
  530.                  active:boolean;
  531.                END;
  532.  
  533.      icon = Array [1..30*48] of byte;  { This is the size of our pictures }
  534.  
  535.      Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }
  536.      VirtPtr = ^Virtual;                  { Pointer to the virtual screen }
  537.  
  538. CONST frame1 : icon = (
  539. 0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,
  540. 7,7,7,7,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
  541. 5,7,7,7,7,7,7,7,8,8,7,7,7,7,7,7,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,
  542. 0,0,0,0,0,5,5,7,7,7,7,7,8,8,7,8,8,7,8,7,8,7,7,7,5,8,8,8,8,5,5,5,5,5,5,5,5,5,5,5,
  543. 5,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,8,7,7,7,8,7,7,7,7,7,7,0,0,0,0,0,0,8,5,5,5,
  544. 5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,7,7,8,8,7,7,8,7,7,8,7,7,7,7,7,0,0,0,0,0,
  545. 0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,7,8,8,8,7,7,8,7,7,8,7,7,7,
  546. 7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,5,7,8,8,8,7,7,
  547. 8,8,8,8,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  548. 9,5,7,8,8,8,8,8,7,7,8,8,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
  549. 1,1,1,1,9,9,9,9,5,7,7,8,8,8,8,7,7,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
  550. 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,5,7,8,8,7,7,8,8,7,8,8,8,7,0,0,0,0,0,0,0,0,0,0,0,0,
  551. 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,5,7,8,8,7,7,7,7,8,8,7,7,7,0,0,0,0,
  552. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7,8,8,8,8,8,8,8,7,
  553. 7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7,
  554. 7,7,7,7,7,7,7,7,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,
  555. 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
  556. 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
  557. 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,
  558. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,
  559. 2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,
  560. 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,
  561. 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,
  562. 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
  563. 0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
  564. 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,
  565. 9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  566. 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
  567. 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  568. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  569. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  570. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  571. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  572. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  573. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  574. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  575. );
  576.       frame2 : icon = (
  577. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  578. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  579. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  580. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  581. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  582. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  583. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  584. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  585. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  586. 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
  587. 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
  588. 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,
  589. 0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
  590. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,
  591. 2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,5,
  592. 5,5,5,5,5,5,5,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,
  593. 1,1,1,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
  594. 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
  595. 0,0,0,0,0,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,
  596. 0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,5,5,5,5,
  597. 5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,
  598. 2,2,2,2,2,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,0,0,0,1,1,1,
  599. 1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,7,1,4,
  600. 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,
  601. 0,0,0,5,5,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,5,5,0,0,
  602. 0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5,
  603. 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  604. 9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
  605. 1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,
  606. 1,7,7,1,7,1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
  607. 0,0,0,0,0,0,0,5,5,1,7,7,7,1,1,5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,
  608. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,
  609. 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,
  610. 0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  611. 0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  612. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  613. );
  614.       frame3 : icon = (
  615. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  616. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  617. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  618. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  619. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  620. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  621. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  622. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  623. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  624. 9,9,9,9,9,9,9,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,1,1,1,1,1,1,1,1,1,1,1,
  625. 1,1,1,1,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,7,1,1,1,1,1,
  626. 1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,
  627. 0,7,1,1,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,1,7,7,7,7,5,5,5,5,5,5,
  628. 5,0,0,0,0,0,0,0,7,1,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,1,1,1,7,7,
  629. 1,1,7,5,5,5,5,5,5,5,0,0,0,0,0,0,1,1,7,1,1,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,
  630. 2,1,7,7,7,1,7,7,7,7,7,5,5,5,5,5,5,5,5,0,0,0,0,0,1,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1,
  631. 1,1,1,2,2,2,2,2,2,1,7,7,7,7,7,7,7,1,1,5,5,5,5,5,5,5,5,5,0,0,0,0,7,7,1,7,1,7,1,1,
  632. 1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,5,5,5,5,5,5,5,5,5,5,5,0,0,0,
  633. 7,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,
  634. 5,5,5,5,5,0,0,0,7,7,0,0,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,
  635. 2,2,5,5,0,0,5,5,0,5,5,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,
  636. 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,
  637. 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,
  638. 4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
  639. 0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
  640. 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,
  641. 9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,
  642. 9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
  643. 1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  644. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  645. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  646. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  647. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  648. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  649. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  650. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  651. );
  652.  
  653.  
  654. VAR Virscr : VirtPtr;                      { Our first Virtual screen }
  655.     VirScr2 : VirtPtr;                     { Our second Virtual screen }
  656.     Vaddr  : word;                      { The segment of our virtual screen}
  657.     Vaddr2 : Word;                      { The segment of our 2nd virt. screen}
  658.     ourpal : Array [0..255,1..3] of byte; { A virtual pallette }
  659.     toaster : Array [1..10] of toastinfo; { The toaster info }
  660.  
  661. {──────────────────────────────────────────────────────────────────────────}
  662. Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }
  663. BEGIN
  664.   asm
  665.      mov        ax,0013h
  666.      int        10h
  667.   end;
  668. END;
  669.  
  670.  
  671. {──────────────────────────────────────────────────────────────────────────}
  672. Procedure SetText;  { This procedure returns you to text mode.  }
  673. BEGIN
  674.   asm
  675.      mov        ax,0003h
  676.      int        10h
  677.   end;
  678. END;
  679.  
  680. {──────────────────────────────────────────────────────────────────────────}
  681. Procedure Cls (Col : Byte; Where:word);
  682.    { This clears the screen to the specified color }
  683. BEGIN
  684.      asm
  685.         push    es
  686.         mov     cx, 32000;
  687.         mov     es,[where]
  688.         xor     di,di
  689.         mov     al,[col]
  690.         mov     ah,al
  691.         rep     stosw
  692.         pop     es
  693.      End;
  694. END;
  695.  
  696.  
  697. {──────────────────────────────────────────────────────────────────────────}
  698. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
  699.   { This puts a pixel on the screen by writing directly to memory. }
  700. BEGIN
  701.   Asm
  702.     push    ds
  703.     push    es
  704.     mov     ax,[where]
  705.     mov     es,ax
  706.     mov     bx,[X]
  707.     mov     dx,[Y]
  708.     push    bx                      {; and this again for later}
  709.     mov     bx, dx                  {; bx = dx}
  710.     mov     dh, dl                  {; dx = dx * 256}
  711.     xor     dl, dl
  712.     shl     bx, 1
  713.     shl     bx, 1
  714.     shl     bx, 1
  715.     shl     bx, 1
  716.     shl     bx, 1
  717.     shl     bx, 1                   {; bx = bx * 64}
  718.     add     dx, bx                  {; dx = dx + bx (ie y*320)}
  719.     pop     bx                      {; get back our x}
  720.     add     bx, dx                  {; finalise location}
  721.     mov     di, bx
  722.     {; es:di = where to go}
  723.     xor     al,al
  724.     mov     ah, [Col]
  725.     mov     es:[di],ah
  726.     pop     es
  727.     pop     ds
  728.   End;
  729. END;
  730.  
  731.  
  732. {──────────────────────────────────────────────────────────────────────────}
  733. procedure WaitRetrace; assembler;
  734.   {  This waits for a vertical retrace to reduce snow on the screen }
  735. label
  736.   l1, l2;
  737. asm
  738.     mov dx,3DAh
  739. l1:
  740.     in al,dx
  741.     and al,08h
  742.     jnz l1
  743. l2:
  744.     in al,dx
  745.     and al,08h
  746.     jz  l2
  747. end;
  748.  
  749.  
  750. {──────────────────────────────────────────────────────────────────────────}
  751. Procedure Pal(Col,R,G,B : Byte);
  752.   { This sets the Red, Green and Blue values of a certain color }
  753. Begin
  754.    asm
  755.       mov    dx,3c8h
  756.       mov    al,[col]
  757.       out    dx,al
  758.       inc    dx
  759.       mov    al,[r]
  760.       out    dx,al
  761.       mov    al,[g]
  762.       out    dx,al
  763.       mov    al,[b]
  764.       out    dx,al
  765.    end;
  766. End;
  767.  
  768. {──────────────────────────────────────────────────────────────────────────}
  769. Procedure GetPal(Col : Byte; Var R,G,B : Byte);
  770.   { This gets the Red, Green and Blue values of a certain color }
  771. Var
  772.    rr,gg,bb : Byte;
  773. Begin
  774.    asm
  775.       mov    dx,3c7h
  776.       mov    al,col
  777.       out    dx,al
  778.  
  779.       add    dx,2
  780.  
  781.       in     al,dx
  782.       mov    [rr],al
  783.       in     al,dx
  784.       mov    [gg],al
  785.       in     al,dx
  786.       mov    [bb],al
  787.    end;
  788.    r := rr;
  789.    g := gg;
  790.    b := bb;
  791. end;
  792.  
  793. {──────────────────────────────────────────────────────────────────────────}
  794. Procedure SetUpVirtual;
  795.    { This sets up the memory needed for the virtual screen }
  796. BEGIN
  797.   GetMem (VirScr,64000);
  798.   vaddr := seg (virscr^);
  799.   GetMem (VirScr2,64000);
  800.   vaddr2 := seg (virscr2^);
  801. END;
  802.  
  803.  
  804. {──────────────────────────────────────────────────────────────────────────}
  805. Procedure ShutDown;
  806.    { This frees the memory used by the virtual screen }
  807. BEGIN
  808.   FreeMem (VirScr,64000);
  809.   FreeMem (VirScr2,64000);
  810. END;
  811.  
  812.  
  813. {──────────────────────────────────────────────────────────────────────────}
  814. procedure flip(source,dest:Word);
  815.   { This copies the entire screen at "source" to destination }
  816. begin
  817.   asm
  818.     push    ds
  819.     mov     ax, [Dest]
  820.     mov     es, ax
  821.     mov     ax, [Source]
  822.     mov     ds, ax
  823.     xor     si, si
  824.     xor     di, di
  825.     mov     cx, 32000
  826.     rep     movsw
  827.     pop     ds
  828.   end;
  829. end;
  830.  
  831.  
  832. {──────────────────────────────────────────────────────────────────────────}
  833. Procedure putico(X,Y:Word;VAR sprt : icon;Where:Word); ASSEMBLER;
  834.   { This puts an icon, EXCEPT it's color 0 (black) pixels, onto the screen
  835.     "where", at position X,Y }
  836. label
  837.   _Redraw, _DrawLoop, _Exit, _LineLoop, _NextLine, _Store, _NoPaint;
  838.  
  839. asm
  840.     push  ds
  841.     push  es
  842.     lds   si,Sprt
  843.     mov   ax,X     { ax = x }
  844.     mov   bx,Y     { bx = y }
  845. _Redraw:
  846.     push    ax
  847.     mov     ax,[where]
  848.     mov     es,ax
  849.  
  850.     mov     ax, bx                  {; ax = bx  x = y}
  851.     mov     bh, bl                  {; y = y * 256  bx = bx * 256}
  852.     xor     bl, bl
  853.     shl     ax, 1
  854.     shl     ax, 1
  855.     shl     ax, 1
  856.     shl     ax, 1
  857.     shl     ax, 1
  858.     shl     ax, 1                   {; y = y * 64   ax = ax * 64}
  859.     add     bx, ax                  {; y = (y*256) + (Y*64)  bx = bx + ax (ie y*320)}
  860.  
  861.     pop     ax                      {; get back our x}
  862.  
  863.  
  864.     add     ax, bx                  {; finalise location}
  865.     mov     di, ax
  866.  
  867.     mov   dl,30    { dl = height of sprite }
  868.     xor   ch,ch
  869.     mov   cl,48     { cx = width of sprite }
  870.     cld
  871.     push  ax
  872.     mov   ax,cx
  873. _DrawLoop:
  874.     push  di            { store y adr. for later }
  875.     mov   cx,ax          { store width }
  876. _LineLoop:
  877.     mov   bl,byte ptr [si]
  878.     or    bl,bl
  879.     jnz   _Store
  880. _NoPaint:
  881.     inc    si
  882.     inc    di
  883.     loop   _LineLoop
  884.     jmp    _NextLine
  885. _Store:
  886.     movsb
  887.     loop  _LineLoop
  888. _NextLine:
  889.     pop   di
  890.     dec   dl
  891.     jz    _Exit
  892.     add   di,320        { di = next line of sprite }
  893.     jmp   _DrawLoop
  894. _Exit:
  895.     pop   ax
  896.     pop   es
  897.     pop   ds
  898. end;
  899.  
  900.  
  901.  
  902.  
  903.  
  904. {──────────────────────────────────────────────────────────────────────────}
  905. Procedure Funny_line(a,b,c,d:integer;where:word);
  906.   { This procedure draws a line from a,b to c,d on screen "where". After
  907.     each pixel it plots, it increments a color counter for the next pixel.
  908.     you may easily alter this to be a normal line procedure, and it will
  909.     be quite a bit faster than the origional one I gave you. This is
  910.     because I replaced all the reals with integers. }
  911.  
  912.   function sgn(a:real):integer;
  913.   begin
  914.        if a>0 then sgn:=+1;
  915.        if a<0 then sgn:=-1;
  916.        if a=0 then sgn:=0;
  917.   end;
  918. var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
  919.     count:integer;
  920. begin
  921.      count:=50;
  922.      u:= c - a;
  923.      v:= d - b;
  924.      d1x:= SGN(u);
  925.      d1y:= SGN(v);
  926.      d2x:= SGN(u);
  927.      d2y:= 0;
  928.      m:= ABS(u);
  929.      n := ABS(v);
  930.      IF NOT (M>N) then
  931.      BEGIN
  932.           d2x := 0 ;
  933.           d2y := SGN(v);
  934.           m := ABS(v);
  935.           n := ABS(u);
  936.      END;
  937.      s := m shr 1;
  938.      FOR i := 0 TO m DO
  939.      BEGIN
  940.           putpixel(a,b,count,where);
  941.           inc (count);
  942.           if count=101 then count:=50;
  943.           s := s + n;
  944.           IF not (s<m) THEN
  945.           BEGIN
  946.                s := s - m;
  947.                a:= a + d1x;
  948.                b := b + d1y;
  949.           END
  950.           ELSE
  951.           BEGIN
  952.                a := a + d2x;
  953.                b := b + d2y;
  954.           END;
  955.      end;
  956. END;
  957.  
  958.  
  959.  
  960. {──────────────────────────────────────────────────────────────────────────}
  961. Procedure SetUpScreen;
  962.   { This procedure sets up the static background to be used in the program }
  963.  
  964. CONST circ : Array [1..5,1..5] of byte =
  965.         ((0,10,10,10,0),
  966.          (10,13,12,11,10),
  967.          (10,12,12,11,10),
  968.          (10,11,11,11,10),
  969.          (0,10,10,10,0));
  970.  
  971. VAR x,y:integer;
  972.     loop1,loop2,loop3:integer;
  973.  
  974. BEGIN
  975.   pal (1,22,22,22);
  976.   pal (2,45,45,45);
  977.   pal (3,59,59,59);
  978.   pal (4,63,63,27);
  979.   pal (5,39,63,3);
  980.   pal (6,51,39,3);
  981.   pal (7,3,27,3);
  982.   pal (8,15,39,15);
  983.   pal (9,35,35,35);
  984.   pal (10, 0, 0,40);
  985.   pal (11,10,10,50);
  986.   pal (12,20,20,60);
  987.   pal (13,30,30,63);
  988.  
  989.   For loop1:=50 to 100 do
  990.     pal (loop1,0,0,loop1-36);
  991.  
  992.   For loop1:=0 to 255 do
  993.      getpal (loop1,OurPal[loop1,1],OurPal[loop1,2],OurPal[loop1,3]);
  994.  
  995.   For loop1:=0 to 319 do
  996.     Funny_line (0,199,loop1,0,vaddr);
  997.   For loop1:=0 to 199 do
  998.     Funny_line (0,199,319,loop1,vaddr);
  999.  
  1000.   For loop1:=1 to 200 do BEGIN
  1001.     x:=random (315);
  1002.     y:=random (195);
  1003.     For loop2:=1 to 5 do
  1004.       For loop3:=1 to 5 do
  1005.         if circ [loop2,loop3]<>0 then
  1006.           putpixel (x+loop2,y+loop3,circ [loop2,loop3],vaddr);
  1007.   END;
  1008.   flip (vaddr,vga);  { Copy the entire screen at vaddr, our virtual screen }
  1009.                      { on which we have done all our graphics, onto the    }
  1010.                      { screen you see, VGA }
  1011.   flip (vaddr,vaddr2);
  1012. END;
  1013.  
  1014.  
  1015. {──────────────────────────────────────────────────────────────────────────}
  1016. Procedure rotatepal;
  1017.   { This procedure rotates the colors between 50 and 100 }
  1018. VAR temp : Array [1..3] of byte;
  1019.     loop1:integer;
  1020. BEGIN
  1021.   Move(OurPal[100],Temp,3);
  1022.   Move(OurPal[50],OurPal[51],50*3);
  1023.   Move(Temp,OurPal[50],3);
  1024.   For loop1:=50 to 100 do
  1025.     pal (loop1,OurPal[loop1,1],OurPal[loop1,2],OurPal[loop1,3]);
  1026. END;
  1027.  
  1028.  
  1029. {──────────────────────────────────────────────────────────────────────────}
  1030. Procedure ScreenTrans (x,y:word);
  1031.   { This is a small procedure to copy a 30x30 pixel block from coordinates
  1032.     x,y on the virtual screen to coordinates x,y on the true vga screen }
  1033. BEGIN
  1034.   asm
  1035.     push    ds
  1036.     push    es
  1037.     mov     ax,vaddr
  1038.     mov     es,ax
  1039.     mov     ax,vaddr2
  1040.     mov     ds,ax
  1041.     mov     bx,[X]
  1042.     mov     dx,[Y]
  1043.     push    bx                      {; and this again for later}
  1044.     mov     bx, dx                  {; bx = dx}
  1045.     mov     dh, dl                  {; dx = dx * 256}
  1046.     xor     dl, dl
  1047.     shl     bx, 1
  1048.     shl     bx, 1
  1049.     shl     bx, 1
  1050.     shl     bx, 1
  1051.     shl     bx, 1
  1052.     shl     bx, 1                   {; bx = bx * 64}
  1053.     add     dx, bx                  {; dx = dx + bx (ie y*320)}
  1054.     pop     bx                      {; get back our x}
  1055.     add     bx, dx                  {; finalise location}
  1056.     mov     di, bx                  {; es:di = where to go}
  1057.     mov     si, di
  1058.     mov     al,60
  1059.     mov     bx, 30         { Hight of block to copy }
  1060. @@1 :
  1061.     mov     cx, 24         { Width of block to copy divided by 2 }
  1062.     rep     movsw
  1063.     add     di,110h        { 320 - 48 = 272 .. or 110 in hex }
  1064.     add     si,110h
  1065.     dec     bx
  1066.     jnz     @@1
  1067.  
  1068.     pop     es
  1069.     pop     ds
  1070.   end;
  1071.   { I wrote this procedure late last night, so it may not be in it's
  1072.     most optimised state. Sorry :-)}
  1073. END;
  1074.  
  1075.  
  1076. {──────────────────────────────────────────────────────────────────────────}
  1077. Procedure NewToaster;
  1078.   { This adds a new toaster to the screen }
  1079. VAR loop1:integer;
  1080. BEGIN
  1081.   loop1:=0;
  1082.   repeat
  1083.     inc (loop1);
  1084.     if not (toaster[loop1].active) then BEGIN
  1085.       toaster[loop1].x:=random (200)+70;
  1086.       toaster[loop1].y:=0;
  1087.       toaster[loop1].active:=true;
  1088.       toaster[loop1].frame:=1;
  1089.       toaster[loop1].speed:=Random (3)+1;
  1090.       loop1:=10;
  1091.     END;
  1092.   until loop1=10;
  1093. END;
  1094.  
  1095.  
  1096. {──────────────────────────────────────────────────────────────────────────}
  1097. Procedure Fly;
  1098.   { This is the procedure where we move and put the toasters }
  1099. VAR loop1,loop2:integer;
  1100.     ch:char;
  1101. BEGIN
  1102.   For loop1:=1 to 10 do
  1103.     toaster[loop1].active:=FALSE;
  1104.   ch:=#0;
  1105.   NewToaster;
  1106.   Repeat
  1107.     if keypressed then BEGIN
  1108.       ch:=readkey;
  1109.       if ch='+' then NewToaster;      { If '+' is pressed, add a toaster }
  1110.       if ch='-' then BEGIN            { if '-' is pressed, remove a toaster }
  1111.         loop1:=0;
  1112.         repeat
  1113.           inc (loop1);
  1114.           if toaster[loop1].active then BEGIN
  1115.             screentrans (toaster[loop1].x,toaster[loop1].y);
  1116.             toaster [loop1].active:=FALSE;
  1117.             loop1:=10;
  1118.           END;
  1119.         until loop1=10;
  1120.       END;
  1121.     END;
  1122.     for loop1:=1 to 10 do
  1123.       if toaster[loop1].active then BEGIN
  1124.         screentrans (toaster[loop1].x,toaster[loop1].y);
  1125.           { Restore the backgrond the toaster was over }
  1126.         dec (toaster[loop1].x,toaster[loop1].speed);
  1127.         inc (toaster[loop1].y,toaster[loop1].speed);
  1128.           { Move the toaster }
  1129.         if (toaster[loop1].x<1) or (toaster[loop1].y>170) then BEGIN
  1130.           toaster[loop1].active:=FALSE;
  1131.           NewToaster;
  1132.         END;
  1133.           { When toaster reaches the edge of the screen, render it inactive
  1134.             and bring a new one into existance. }
  1135.       END;
  1136.     for loop1:=1 to 10 do
  1137.       if toaster[loop1].active then BEGIN
  1138.         CASE toaster [loop1].frame of
  1139.            1   : putico (toaster[loop1].x,toaster[loop1].y,frame1,vaddr);
  1140.            3   : putico (toaster[loop1].x,toaster[loop1].y,frame2,vaddr);
  1141.            2,4 : putico (toaster[loop1].x,toaster[loop1].y,frame3,vaddr);
  1142.         END;
  1143.         toaster[loop1].frame:=toaster[loop1].frame+1;
  1144.         if toaster [loop1].frame=5 then toaster[loop1].frame:=1;
  1145.           { Draw all the toasters on the VGA screen }
  1146.       END;
  1147.     waitretrace;
  1148.     flip (vaddr,vga);
  1149.     rotatepal;
  1150.   Until ch=#27;
  1151. END;
  1152.  
  1153.  
  1154. BEGIN
  1155.   Randomize;       { Make sure that the RANDOM funcion really is random }
  1156.   SetupVirtual;    { Set up virtual page, VADDR }
  1157.   ClrScr;
  1158.   writeln ('Hello! This program will demonstrate the principals of animation.');
  1159.   writeln ('The program will firstly generate an arb background screen to a');
  1160.   writeln ('virtual page, then flip it to the VGA. A toaster will then start');
  1161.   writeln ('to move across the screen. Note that the background will be restored');
  1162.   writeln ('after the toaster has passed over it. You may add or remove toasters');
  1163.   writeln ('by hitting "+" or "-" respectively. Note that the more frames you');
  1164.   writeln ('use, usually the better the routine looks. Because of space');
  1165.   writeln ('restrictions, we only had room for three frames.');
  1166.   writeln;
  1167.   writeln ('The toasters were drawn by Fubar (Pieter Buys) in Autodesk Animator.');
  1168.   writeln ('I wrote a small little program to convert them into CONSTANTS. See');
  1169.   writeln ('the main text to find out how to load up AA CEL files directly.');
  1170.   writeln;
  1171.   writeln;
  1172.   Write ('  Hit any key to contine ...');
  1173.   Readkey;
  1174.   SetMCGA;
  1175.   SetupScreen;     { Draw the background screen to VADDR, then flip it to
  1176.                      the VGA screen }
  1177.   Fly;             { Make the toasters fly around the screen }
  1178.   SetText;
  1179.   ShutDown;        { Free the memory taken up by virtual page }
  1180.   Writeln ('All done. This concludes the seventh sample program in the ASPHYXIA');
  1181.   Writeln ('Training series. You may reach DENTHOR under the names of GRANT');
  1182.   Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid');
  1183.   Writeln ('Connectix BBS user, which is unfortunatly offline for the moment.');
  1184.   Writeln ('For discussion purposes, I am also the moderator of the Programming');
  1185.   Writeln ('newsgroup on the For Your Eyes Only BBS.');
  1186.   Writeln ('The numbers are available in the main text. You may also write to me at:');
  1187.   Writeln ('             Grant Smith');
  1188.   Writeln ('             P.O. Box 270');
  1189.   Writeln ('             Kloof');
  1190.   Writeln ('             3640');
  1191.   Writeln ('I hope to hear from you soon!');
  1192.   Writeln; Writeln;
  1193.   Write   ('Hit any key to exit ...');
  1194.   Readkey;
  1195. END.
  1196.